package com.mtf.syncExportExcel.entity;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
import com.google.common.collect.Lists;
import com.mtf.syncExportExcel.handle.EasyExportExcelHandle;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

@Slf4j
public class EasyExcelExport<E, P> {

    private ExportContext<E, P> context;

    private EasyExcelExport() {
    }

    private EasyExcelExport(ExportContext<E, P> context) {
        this.context = context;
    }

    /**
     * 用于oss文件异步导出
     *
     * @param fileName
     * @throws IOException
     */
    public void export(String fileName) throws IOException {
        File file = File.createTempFile(fileName, ".xlsx",new File("D:\\code\\MyBaby\\mq_idempotent\\MqResolveIdempotent\\file"));
        context.setFile(file);
        try {
            export(new FileOutputStream(file));
        } finally {
            try {
                // 删除临时文件
                //file.delete();
            } catch (Exception e) {
                log.error("删除文件失败", e);
            }
        }
    }

    /**
     * 用于reponse同步导出
     *
     * @param outputStream
     */
    public void export(OutputStream outputStream) {
        try {
            EasyExportExcelHandle<E, P> exportHandle = context.getExportHandle();
            exportHandle.beforeExportData(context);
            ExcelWriter excelWriter = EasyExcel.write(outputStream, context.getClz()).build();
            // sheet页限制
            int maxSheetLine = context.getMaxSheetLine();
            // 当前sheet页
            int sheetNo = 0;
            WriteTable writeTable = exportHandle.getWriteTable();
            WriteSheet writeSheet = EasyExcel.writerSheet(sheetNo, context.getSheetName() + sheetNo).build();
            // 初始化合计行
            exportHandle.initSumLine();
            // 当前sheet页数据行数
            int currSheetLine = 0;
            // 所有sheet页总行数
            int allSheetLine = 0;
            // 限制记录数
            int limitAllSheetLine = context.getLimitAllSheetLine();
            List<P> partition = exportHandle.getPartition();
            int pageNo = 0;
            // 设置查询页码
            context.setPageNo(pageNo);
            List<E> data = exportHandle.loadData(context);
            excelWriter.write(data, writeSheet, writeTable);
            int size = data.size();
            // 当前页数 + 1
            pageNo++;
            currSheetLine += size;
            allSheetLine += size;
            excelWriter.write(data, writeSheet, writeTable);
            data.clear();
            // 合计行
            E sumLine = exportHandle.getSumLine();
            // 有合计数据且当前sheet页有数据
            if (sumLine != null && currSheetLine > 0) {
                List<E> list = Lists.newArrayList();
                list.add(sumLine);
                excelWriter.write(list, writeSheet, writeTable);
            }
            excelWriter.finish();
            // 导出后做啥
            exportHandle.afterExportData(context);
        } catch (Exception e){
            log.info("打印异常信息：{}",e.getMessage());
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (Exception e) {
                    log.error("关闭输出流失败", e);
                }
            }
        }
    }

    @Getter
    @Setter
    public static class ExportContext<E, P> {

        private Class clz;

        private String sheetName;

        // 页码
        private int pageNo;

        // 查询页大小
        private int pageSize;

        // sheet页限制最大行数
        private int maxSheetLine;

        // 限制导出条数
        private int limitAllSheetLine;

        // 分片条件
        private P term;

        // 文件 用于oss 上传文件
        private File file;

        // 一般的导出不需要扩展
        private EasyExportExcelHandle<E, P> exportHandle;
    }

    /**
     * @param <E>
     * @param <P>
     */
    public static class Builder<E, P> {
        //
        private Class clz;

        //
        private String sheetName;

        // 查询页大小
        private int pageSize = 1000;

        // sheet页限制最大行数
        private int maxSheetLine = 500000;

        // 限制导出条数
        private int limitAllSheetLine = 500000;

        //
        private EasyExportExcelHandle<E, P> exportHandle;

        public Builder<E, P> setClz(Class clz) {
            this.clz = clz;
            return this;
        }

        public Builder<E, P> setSheetName(String sheetName) {
            this.sheetName = sheetName;
            return this;
        }

        public Builder<E, P> setPageSize(int pageSize) {
            this.pageSize = pageSize;
            return this;
        }

        public Builder<E, P> setMaxSheetLine(int maxSheetLine) {
            this.maxSheetLine = maxSheetLine;
            return this;
        }

        public Builder<E, P> setLimitAllSheetLine(int limitAllSheetLine) {
            this.limitAllSheetLine = limitAllSheetLine;
            return this;
        }

        public Builder<E, P> setExportHandle(EasyExportExcelHandle<E, P> exportHandle) {
            this.exportHandle = exportHandle;
            return this;
        }

        public EasyExcelExport<E, P> create() {
            ExportContext<E, P> context = new ExportContext<>();
            context.setClz(this.clz);
            context.setSheetName(this.sheetName);
            context.setPageSize(this.pageSize);
            context.setMaxSheetLine(this.maxSheetLine);
            context.setLimitAllSheetLine(this.limitAllSheetLine);
            context.setExportHandle(this.exportHandle);
            return new EasyExcelExport<>(context);
        }
    }

    /**
     * @param <E>
     * @param <P>
     * @return
     */
    public static <E, P> Builder<E, P> bulider() {
        return new Builder<>();
    }
}
